package com.wofish.member.service.impl;

import com.wofish.common.constant.Constants;
import com.wofish.common.core.text.Convert;
import com.wofish.framework.util.ShiroUtils;
import com.wofish.member.domain.MemberPoint;
import com.wofish.member.domain.MemberPointRecord;
import com.wofish.member.enums.AdvanceTypeEnum;
import com.wofish.member.domain.Member;
import com.wofish.member.domain.MemberAdvance;
import com.wofish.member.enums.PointTypeEnum;
import com.wofish.member.mapper.MemberAdvanceMapper;
import com.wofish.member.mapper.MemberMapper;
import com.wofish.member.mapper.MemberPointMapper;
import com.wofish.member.mapper.MemberPointRecordMapper;
import com.wofish.member.service.IMemberService;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 会员 服务层实现
 * 
 * @author wofish
 * @date 2019-04-21
 */
@Service
public class MemberServiceImpl implements IMemberService {
	@Autowired
	private MemberMapper memberMapper;
	@Autowired
	private MemberPointMapper memberPointMapper;
	@Autowired
	private MemberPointRecordMapper memberPointRecordMapper;
	@Autowired
	private MemberAdvanceMapper memberAdvanceMapper;

	private static Logger logger = LoggerFactory.getLogger(MemberServiceImpl.class);
	/**
     * 查询会员信息
     * 
     * @param memberId 会员ID
     * @return 会员信息
     */
    @Override
	public Member selectMemberById(Long memberId) {
	    return memberMapper.selectMemberById(memberId);
	}

	/**
     * 查询会员列表
     * 
     * @param member 会员信息
     * @return 会员集合
     */
	@Override
	public List<Member> selectMemberList(Member member) {
	    return memberMapper.selectMemberList(member);
	}
	
    /**
     * 新增会员
     * 
     * @param member 会员信息
     * @return 结果
     */
	@Override
	public int insertMember(Member member) {
		Date date = new Date();
		member.setRegTime(date);
		member.setUpdateTime(date);
	    return memberMapper.insertMember(member);
	}
	
	/**
     * 修改会员
     * 
     * @param member 会员信息
     * @return 结果
     */
	@Override
	public int updateMember(Member member) {
		member.setUpdateTime(new Date());
	    return memberMapper.updateMember(member);
	}

	/**
     * 删除会员对象
     * 
     * @param ids 需要删除的数据ID
     * @return 结果
     */
	@Override
	public int deleteMemberByIds(String ids) {
		return memberMapper.deleteMemberByIds(Convert.toStrArray(ids));
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public int addMemberAdvance(Long memberId, BigDecimal val, String reason, AdvanceTypeEnum type) {
		int result = memberMapper.updateMemberAdvance(memberId, val);
		if(result > 0) {
			Member member = memberMapper.selectMemberById(memberId);
			MemberAdvance memberAdvance = new MemberAdvance();
			memberAdvance.setMemberAdvance(member.getAdvance());
			memberAdvance.setMemberId(memberId);
			if((type.getFlag() == -1 && val.doubleValue() > 0)
					|| (type.getFlag() == 1 && val.doubleValue() < 0)) {
			    val = val.multiply(BigDecimal.valueOf(-1));
			}
			memberAdvance.setMoney(val);
			//todo 获取当前登录用户
			memberAdvance.setOperator(ShiroUtils.getUsername());
			memberAdvance.setOperatorId(ShiroUtils.getUserId());
			memberAdvance.setRemark(reason);
			memberAdvance.setType(type.getType());
			memberAdvance.setCreateTime(new Date());
		    memberAdvanceMapper.insertMemberAdvance(memberAdvance);
		}
		return result;
	}


	/**
	 * 处理会员积分添加
	 *
	 * @param memberId
	 * @param newVal： 可正可负
	 * @param reason
	 * @param admin
	 * @return
	 */
	@Override
	public boolean addMemberPoint(Long memberId, Integer newVal, String reason, PointTypeEnum admin) {
		if(newVal < 0) {
			//积分值小于0，表示消耗积分，此时需要将积分值转成正数
			return usePoint(memberId, null, -newVal, PointTypeEnum.admin, reason);
		} else {
			return addPoint(memberId, null, newVal, PointTypeEnum.admin, reason);
		}
	}

	/**
	 * 使用积分
	 *
	 * 使用时，先过期的积分优先使用
	 * @param memberId
	 * @param orderId
	 * @param point: 积分值大于0
	 * @param type
	 * @param reason
	 * @return
	 *
	 * todo:获取当前登录用户
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean usePoint(Long memberId, Long orderId, Integer point, PointTypeEnum type, String reason) {
		if(null == memberId) {
			throw new IllegalArgumentException("积分使用失败，会员id为空！");
		}
		if(null == point || point == 0) {
			return true;
		}
		if(point < 0) {
			throw new RuntimeException("积分使用值应大于0");
		}
		//更新会员积分值, 消耗时，积分值转成负数
		int result = memberMapper.updateMemberPoint(memberId, -point);
		if(result <= 0) {
			throw new RuntimeException("使用积分失败，会员"+memberId+"积分可能不足！");
		}
		long pageNo = 0;
		long pageSize = 10;
		int sumPoint = 0;
		//目标记录
		MemberPointRecord targetRecord = null;
		//保存要更新的recordId
		List<Long> recordIds = new ArrayList<>();
		//查询条件
		MemberPointRecord search = new MemberPointRecord();
		search.setMemberId(memberId);
		search.setFlag(Constants.DISABLE_1);
		search.setOrderFields(" expire_time ASC ");
		while(sumPoint < point) {
			search.setOffset(pageNo * pageSize);
			search.setLimit(pageSize);
			List<MemberPointRecord> pointRecords = memberPointRecordMapper.selectMemberPointRecordList(search);
			if(CollectionUtils.isEmpty(pointRecords)) {
				break;
			}
			for(MemberPointRecord pointRecord : pointRecords) {
				sumPoint += pointRecord.getPoint();
				if(sumPoint >= point) {
					targetRecord = pointRecord;
					break;
				}
				recordIds.add(pointRecord.getRecordId());
			}
			pageNo++;
		}
		if(sumPoint < point) {
			//当前积分不足以消耗
			logger.warn("用户积分不足！会员id:{},当前可用积分：{},消耗积分:{}", memberId, sumPoint, point);
			return false;
		} else if(sumPoint == point) {
			recordIds.add(targetRecord.getRecordId());
		} else {
			/**
			 * 需要将targetRecord拆成两条记录
			 */
			int leftPoint = sumPoint - point;
			int usePoint = targetRecord.getPoint() - leftPoint;
			//添加一条记录
			MemberPointRecord newPointRecord = new MemberPointRecord();
			newPointRecord.setCreateTime(targetRecord.getCreateTime());
			newPointRecord.setExpireTime(targetRecord.getExpireTime());
			newPointRecord.setMemberId(targetRecord.getMemberId());
			newPointRecord.setOrigRecordId(targetRecord.getRecordId());
			newPointRecord.setPoint(leftPoint);
			newPointRecord.setUpdateTime(new Date());
			memberPointRecordMapper.insertMemberPointRecord(newPointRecord);

			//targetId对应的记录，point进行扣减
			MemberPointRecord updateModel = new MemberPointRecord();
			updateModel.setRecordId(targetRecord.getRecordId());
			updateModel.setPoint(usePoint);
			updateModel.setFlag(Constants.DISABLE_0);
			updateModel.setUpdateTime(new Date());
			updateModel.setOrderId(orderId);
			memberPointRecordMapper.updateMemberPointRecord(updateModel);
		}
		//recordIds对应的记录，此时积分已用完，更新记录状态
		if(CollectionUtils.isNotEmpty(recordIds)) {
			MemberPointRecord updatePointRecord = new MemberPointRecord();
			updatePointRecord.setUpdateTime(new Date());
			updatePointRecord.setOrderId(orderId);
			updatePointRecord.setFlag(Constants.DISABLE_0);
			//params
			Map<String, Object> params = new HashMap<>(4);
			params.put("recordIds", recordIds);
			updatePointRecord.setParams(params);
			memberPointRecordMapper.updateRecord(updatePointRecord);
		}
		//添加一条会员积分明细
        Date expireTime = null;
		MemberPoint memberPoint = new MemberPoint();
		memberPoint.setChangePoint(-point);
		memberPoint.setCreateTime(new Date());
		memberPoint.setMemberId(memberId);
		memberPoint.setRemark(type.getDesc());
		memberPoint.setPoint(memberMapper.selectMemberById(memberId).getPoint());
		memberPoint.setReason(reason);
		memberPoint.setRelatedId(orderId);
		memberPoint.setType(type.getType());
		memberPoint.setExpireTime(expireTime);
		memberPoint.setOperator(ShiroUtils.getUsername());
		memberPoint.setOperatorId(ShiroUtils.getUserId());
		memberPointMapper.insertMemberPoint(memberPoint);
		return true;
	}

	/**
	 * 添加一条积分
	 *
	 * @param memberId
	 * @param orderId
	 * @param point: 积分值需大于0
	 * @param type
	 * @param reason
	 * @return
	 *
	 * todo: 1.积分过期时间, 2.获取当前登录用户
	 *
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean addPoint(Long memberId, Long orderId, Integer point, PointTypeEnum type, String reason) {
		if(null == memberId) {
			throw new IllegalArgumentException("积分添加失败，会员id为空！");
		}
		if(null == point || point == 0) {
			return true;
		}
		if(point < 0) {
			throw new RuntimeException("积分添加值应大于0");
		}
		//更新会员积分值
		int result = memberMapper.updateMemberPoint(memberId, point);
		if(result <= 0) {
			throw new RuntimeException("使用积分失败，会员"+memberId+"积分可能不足！");
		}
		Date now = new Date();
		Date expireTime = null;
		//添加一条记录
		MemberPointRecord newPointRecord = new MemberPointRecord();
		newPointRecord.setFlag(Constants.DISABLE_1);
		newPointRecord.setOrderId(orderId);
		newPointRecord.setMemberId(memberId);
		newPointRecord.setPoint(point);
		newPointRecord.setExpireTime(expireTime);
		newPointRecord.setCreateTime(now);
		newPointRecord.setUpdateTime(now);
		memberPointRecordMapper.insertMemberPointRecord(newPointRecord);
		//添加一条会员积分明细
		MemberPoint memberPoint = new MemberPoint();
		memberPoint.setChangePoint(point);
		memberPoint.setCreateTime(now);
		memberPoint.setMemberId(memberId);
		memberPoint.setRemark(type.getDesc());
		memberPoint.setPoint(memberMapper.selectMemberById(memberId).getPoint());
		memberPoint.setReason(reason);
		memberPoint.setRelatedId(orderId);
		memberPoint.setType(type.getType());
		memberPoint.setExpireTime(expireTime);
		memberPoint.setOperator(ShiroUtils.getUsername());
		memberPoint.setOperatorId(ShiroUtils.getUserId());
		memberPointMapper.insertMemberPoint(memberPoint);
		return true;
	}

	/**
	 * 更新过期积分
	 *
	 * @param memberId
	 * @param date
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public int updateExpirePoint(Long memberId, Date date) {
		if(null == memberId || null == date) {
			throw new IllegalArgumentException("统计失败，会员id或统计时间为空！");
		}
		//统计当前未过期积分，不包括冻结积分
		MemberPointRecord sumSearch = new MemberPointRecord();
		sumSearch.setMemberId(memberId);
		sumSearch.setFlag(Constants.DISABLE_1);
		//params参数
		Map<String, Object> params = new HashMap<>(4);
		params.put("expireTimeStart", date);
		sumSearch.setParams(params);
		Integer point = memberPointRecordMapper.sumPoint(sumSearch);
		//统计过期积分，不包含冻结积分
		MemberPointRecord expireSearch = new MemberPointRecord();
		expireSearch.setMemberId(memberId);
		expireSearch.setFlag(Constants.DISABLE_1);
		//params参数
		Map<String, Object> expireParams = new HashMap<>(4);
		expireParams.put("expireTimeEnd", date);
		sumSearch.setParams(expireParams);
		Integer expirePoint = memberPointRecordMapper.sumPoint(expireSearch);
		if(null != expirePoint && expirePoint > 0) {
			//添加一条过期积分消耗明细
			MemberPoint memberPoint = new MemberPoint();
			memberPoint.setMemberId(memberId);
			memberPoint.setPoint(point);
			memberPoint.setReason(PointTypeEnum.expire.getDesc());
			memberPoint.setRemark("系统扣除过期积分");
			memberPoint.setType(PointTypeEnum.expire.getType());
			memberPoint.setCreateTime(date);
			memberPoint.setChangePoint(-1 * expirePoint);
			memberPointMapper.insertMemberPoint(memberPoint);
			//更新过期的记录
			MemberPointRecord updateModel = new MemberPointRecord();
			updateModel.setUpdateTime(new Date());
			updateModel.setFlag(Constants.DISABLE_0);
			//params参数
			Map<String, Object> updateParams = new HashMap<>(4);
			updateParams.put("expireTimeEnd", date);
			updateParams.put("memberId", memberId);
			updateModel.setParams(updateParams);
			memberPointRecordMapper.updateRecord(updateModel);
			//更新会员积分总额
			Member member = new Member();
			member.setMemberId(memberId);
			member.setPoint(point);
			memberMapper.updateMember(member);
		}
		return point;
	}

}
